﻿/*
  Copyright © Alexander G. Bykin, Russia 2009-2010
  This source is subject to the Microsoft Public License (Ms-PL).
  Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
  All other rights reserved.
*/

namespace System.Windows.Controls
{
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Windows.Controls.Data;
    using System.Windows.Controls.Primitives;
    using System.Windows.Input;
    using System.Windows.Media.Imaging;

    /// <summary>
    /// Customizable DomainDataSource Filter descriptors.
    /// </summary>
    /// <QualityBand>Stable</QualityBand>
    [TemplatePart(Name = "btnAddFilter", Type = typeof(ButtonBase))]
    [TemplatePart(Name = "btnDeleteFilter", Type = typeof(ButtonBase))]
    [TemplatePart(Name = "btnClearFilter", Type = typeof(ButtonBase))]
    [TemplatePart(Name = "btnApply", Type = typeof(ButtonBase))]
    [TemplatePart(Name = "btnCancel", Type = typeof(ButtonBase))]
    [TemplatePart(Name = "dgcFilterPropertyPath", Type = typeof(DataGridColumn))]
    [TemplatePart(Name = "dgcFilterOperation", Type = typeof(DataGridColumn))]
    [TemplatePart(Name = "dgcFilterValue", Type = typeof(DataGridColumn))]
    [TemplatePart(Name = "dgcFilterIgnoreValue", Type = typeof(DataGridColumn))]
    [TemplatePart(Name = "dgcFilterIsCaseSensitive", Type = typeof(DataGridColumn))]
    [TemplatePart(Name = "dgFilter", Type = typeof(DataGrid))]
    [TemplatePart(Name = "deleteRowCmd", Type = typeof(DynaCommand))]
    [TemplatePart(Name = "deleteRowToolTip", Type = typeof(DynaObject))]
    [TemplatePart(Name = "switchFieldsComboOrderByCmd", Type = typeof(DynaCommand))]
    [TemplatePart(Name = "switchFieldsComboOrderByToolTip", Type = typeof(DynaObject))]
    [TemplatePart(Name = "fieldsComboOrderByImage", Type = typeof(DynaObject))]
    public class DataFilter : Control
    {
        #region Constants

        /// <summary>
        /// The default order to use when there is no <see cref="DisplayAttribute.Order"/>
        /// value available for the property.
        /// </summary>
        /// <remarks>
        /// The value of 10000 is a standard default value, allowing
        /// some properties to be ordered at the beginning and some at the end.
        /// </remarks>
        private const int UnspecifiedOrder = 10000;

        private const string DATAFILTER_elementButtonAddFilter = "btnAddFilter";
        private const string DATAFILTER_elementButtonDeleteFilter = "btnDeleteFilter";
        private const string DATAFILTER_elementButtonClearFilter = "btnClearFilter";
        private const string DATAFILTER_elementButtonApply = "btnApply";
        private const string DATAFILTER_elementButtonCancel = "btnCancel";
        private const string DATAFILTER_elementDataGridColumnFilterPropertyPath = "dgcFilterPropertyPath";
        private const string DATAFILTER_elementDataGridColumnFilterPropertyPathHeader = "dgcFilterPropertyPathHeader";
        private const string DATAFILTER_elementDataGridColumnFilterOperation = "dgcFilterOperation";
        private const string DATAFILTER_elementDataGridColumnFilterValue = "dgcFilterValue";
        private const string DATAFILTER_elementDataGridColumnFilterIgnoreValue = "dgcFilterIgnoreValue";
        private const string DATAFILTER_elementDataGridColumnFilterIsCaseSensitive = "dgcFilterIsCaseSensitive";
        private const string DATAFILTER_elementDataGridFilter = "dgFilter";
        private const string DATAFILTER_elementDeleteRowCmd = "deleteRowCmd";
        private const string DATAFILTER_elementDeleteRowToolTip = "deleteRowToolTip";
        private const string DATAFILTER_elementSwitchFieldsComboOrderByCmd = "switchFieldsComboOrderByCmd";
        private const string DATAFILTER_elementSwitchFieldsComboOrderByToolTip = "switchFieldsComboOrderByToolTip";
        private const string DATAFILTER_elementFieldsComboOrderByImage = "fieldsComboOrderByImage";

        private const string DATAFILTER_DefaultButtonAddFilterTooltip = "Add Filter";
        private const string DATAFILTER_DefaultButtonDeleteFilterTooltip = "Remove Filter";
        private const string DATAFILTER_DefaultButtonClearFilterTooltip = "Clear Filter";
        private const string DATAFILTER_DefaultButtonApplyContent = "Apply";
        private const string DATAFILTER_DefaultButtonCancelContent = "Cancel";
        private const string DATAFILTER_DefaultButtonApplyTooltip = "Apply filters";
        private const string DATAFILTER_DefaultButtonCancelTooltip = "Cancel filters";
        private const string DATAFILTER_DefaultDataGridColumnFilterPropertyPath = "Field name";
        private const string DATAFILTER_DefaultDataGridColumnFilterOperation = "Operation";
        private const string DATAFILTER_DefaultDataGridColumnFilterValue = "Value";
        private const string DATAFILTER_DefaultDataGridColumnFilterIgnoreValue = "Ignore value";
        private const string DATAFILTER_DefaultDataGridColumnFilterIsCaseSensitive = "Is Case Sensitive ?";
        private const string DATAFILTER_DefaultButtonSwitchFieldsComboOrderByTooltip = "Change 'Field name' combobox sort order";

        #endregion

        #region Dependency Properties

        #region DependencyProperty DomainEntityFieldCollection

        /// <summary>
        /// Identifies the DomainEntityFieldCollection dependency property.
        /// </summary>
        public static readonly DependencyProperty DomainEntityFieldCollectionProperty =
            DependencyProperty.Register(
                "DomainEntityFieldCollection",
                typeof(DomainEntityFieldCollection),
                typeof(DataFilter),
                new PropertyMetadata(new DomainEntityFieldCollection(), OnDomainEntityFieldCollectionPropertyChanged));

        /// <summary>
        /// DomainEntityFieldCollection property changed handler.
        /// </summary>
        /// <param name="d">DataFilter that changed its DomainEntityFieldCollection value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnDomainEntityFieldCollectionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataFilter control = d as DataFilter;
            if (control == null)
            {
                return;
            }

            //control.DomainEntityFieldCollection = e.NewValue as DomainEntityFieldCollection;
            control.RefreshListOfDomainEntityFields();
            control.RefreshFilterItems();
        }

        #endregion

        #region DependencyProperty FilterOperatorLocalizationCollection

        /// <summary>
        /// Identifies the FilterOperatorLocalizationCollection dependency property.
        /// </summary>
        public static readonly DependencyProperty FilterOperatorLocalizationCollectionProperty =
            DependencyProperty.Register(
                "FilterOperatorLocalizationCollection",
                typeof(FilterOperatorLocalizationCollection),
                typeof(DataFilter),
                new PropertyMetadata(OnFilterOperatorLocalizationCollectionPropertyChanged));

        /// <summary>
        /// FilterOperatorLocalizationCollection property changed handler.
        /// </summary>
        /// <param name="d">DataFilter that changed its FilterOperatorLocalizationCollection value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnFilterOperatorLocalizationCollectionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataFilter control = d as DataFilter;
            if (control == null)
            {
                return;
            }

            //control.FilterOperatorLocalizationCollection = e.NewValue as FilterOperatorLocalizationCollection;

        }

        #endregion

        #region DependencyProperty ButtonAddFilterTooltip

        /// <summary>
        /// Identifies the ButtonAddFilterTooltip dependency property.
        /// </summary>
        public static readonly DependencyProperty ButtonAddFilterTooltipProperty =
            DependencyProperty.Register(
                "ButtonAddFilterTooltip",
                typeof(string),
                typeof(DataFilter),
                new PropertyMetadata(DATAFILTER_DefaultButtonAddFilterTooltip, OnButtonAddFilterTooltipPropertyChanged));

        /// <summary>
        /// ButtonAddFilterTooltip property changed handler.
        /// </summary>
        /// <param name="d">DataFilter that changed its ButtonAddFilterTooltip value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnButtonAddFilterTooltipPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataFilter control = d as DataFilter;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.btnAddFilter != null &&
                !string.IsNullOrEmpty(newValue))
            {
                ToolTipService.SetToolTip(control.btnAddFilter, newValue);
            }
        }

        #endregion

        #region DependencyProperty ButtonDeleteFilterTooltip

        /// <summary>
        /// Identifies the ButtonDeleteFilterTooltip dependency property.
        /// </summary>
        public static readonly DependencyProperty ButtonDeleteFilterTooltipProperty =
            DependencyProperty.Register(
                "ButtonDeleteFilterTooltip",
                typeof(string),
                typeof(DataFilter),
                new PropertyMetadata(DATAFILTER_DefaultButtonDeleteFilterTooltip, OnButtonDeleteFilterTooltipPropertyChanged));

        /// <summary>
        /// ButtonDeleteFilterTooltip property changed handler.
        /// </summary>
        /// <param name="d">DataFilter that changed its ButtonDeleteFilterTooltip value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnButtonDeleteFilterTooltipPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataFilter control = d as DataFilter;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.btnDeleteFilter != null &&
                !string.IsNullOrEmpty(newValue))
            {
                ToolTipService.SetToolTip(control.btnDeleteFilter, newValue);
                if (control.dgFilter != null)
                  ((DynaObject)control.dgFilter.Resources[DATAFILTER_elementDeleteRowToolTip]).Value = newValue;
            }
        }

        #endregion

        #region DependencyProperty ButtonClearFilterTooltip

        /// <summary>
        /// Identifies the ButtonClearFilterTooltip dependency property.
        /// </summary>
        public static readonly DependencyProperty ButtonClearFilterTooltipProperty =
            DependencyProperty.Register(
                "ButtonClearFilterTooltip",
                typeof(string),
                typeof(DataFilter),
                new PropertyMetadata(DATAFILTER_DefaultButtonClearFilterTooltip, OnButtonClearFilterTooltipPropertyChanged));

        /// <summary>
        /// ButtonClearFilterTooltip property changed handler.
        /// </summary>
        /// <param name="d">DataFilter that changed its ButtonClearFilterTooltip value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnButtonClearFilterTooltipPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataFilter control = d as DataFilter;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.btnClearFilter != null &&
                !string.IsNullOrEmpty(newValue))
            {
                ToolTipService.SetToolTip(control.btnClearFilter, newValue);
            }
        }

        #endregion

        #region DependencyProperty ButtonApplyContent

        /// <summary>
        /// Identifies the ButtonApplyContent dependency property.
        /// </summary>
        public static readonly DependencyProperty ButtonApplyContentProperty =
            DependencyProperty.Register(
                "ButtonApplyContent",
                typeof(string),
                typeof(DataFilter),
                new PropertyMetadata(DATAFILTER_DefaultButtonApplyContent, OnButtonApplyContentPropertyChanged));

        /// <summary>
        /// ButtonApplyContent property changed handler.
        /// </summary>
        /// <param name="d">DataFilter that changed its ButtonApplyContent value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnButtonApplyContentPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataFilter control = d as DataFilter;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.btnApply != null &&
                !string.IsNullOrEmpty(newValue))
            {
                control.btnApply.Content = newValue;
            }
        }

        #endregion

        #region DependencyProperty ButtonCancelContent

        /// <summary>
        /// Identifies the ButtonCancelContent dependency property.
        /// </summary>
        public static readonly DependencyProperty ButtonCancelContentProperty =
            DependencyProperty.Register(
                "ButtonCancelContent",
                typeof(string),
                typeof(DataFilter),
                new PropertyMetadata(DATAFILTER_DefaultButtonCancelContent, OnButtonCancelContentPropertyChanged));

        /// <summary>
        /// ButtonCancelContent property changed handler.
        /// </summary>
        /// <param name="d">DataFilter that changed its ButtonCancelContent value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnButtonCancelContentPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataFilter control = d as DataFilter;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.btnCancel != null &&
                !string.IsNullOrEmpty(newValue))
            {
                control.btnCancel.Content = newValue;
            }
        }

        #endregion

        #region DependencyProperty ButtonApplyTooltip

        /// <summary>
        /// Identifies the ButtonApplyTooltip dependency property.
        /// </summary>
        public static readonly DependencyProperty ButtonApplyTooltipProperty =
            DependencyProperty.Register(
                "ButtonApplyTooltip",
                typeof(string),
                typeof(DataFilter),
                new PropertyMetadata(DATAFILTER_DefaultButtonApplyTooltip, OnButtonApplyTooltipPropertyChanged));

        /// <summary>
        /// ButtonApplyTooltip property changed handler.
        /// </summary>
        /// <param name="d">DataFilter that changed its ButtonApplyTooltip value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnButtonApplyTooltipPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataFilter control = d as DataFilter;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.btnApply != null &&
                !string.IsNullOrEmpty(newValue))
            {
                ToolTipService.SetToolTip(control.btnApply, newValue);
            }
        }

        #endregion

        #region DependencyProperty ButtonCancelTooltip

        /// <summary>
        /// Identifies the ButtonCancelTooltip dependency property.
        /// </summary>
        public static readonly DependencyProperty ButtonCancelTooltipProperty =
            DependencyProperty.Register(
                "ButtonCancelTooltip",
                typeof(string),
                typeof(DataFilter),
                new PropertyMetadata(DATAFILTER_DefaultButtonCancelTooltip, OnButtonCancelTooltipPropertyChanged));

        /// <summary>
        /// ButtonCancelTooltip property changed handler.
        /// </summary>
        /// <param name="d">DataFilter that changed its ButtonCancelTooltip value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnButtonCancelTooltipPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataFilter control = d as DataFilter;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.btnCancel != null &&
                !string.IsNullOrEmpty(newValue))
            {
                ToolTipService.SetToolTip(control.btnCancel, newValue);
            }
        }

        #endregion

        #region DependencyProperty ButtonSwitchFieldsComboOrderByTooltip

        /// <summary>
        /// Identifies the ButtonSwitchFieldsComboOrderByTooltip dependency property.
        /// </summary>
        public static readonly DependencyProperty ButtonSwitchFieldsComboOrderByTooltipProperty =
            DependencyProperty.Register(
                "ButtonSwitchFieldsComboOrderByTooltip",
                typeof(string),
                typeof(DataFilter),
                new PropertyMetadata(DATAFILTER_DefaultButtonSwitchFieldsComboOrderByTooltip, OnButtonSwitchFieldsComboOrderByTooltipPropertyChanged));

        /// <summary>
        /// ButtonSwitchFieldsComboOrderByTooltip property changed handler.
        /// </summary>
        /// <param name="d">DataFilter that changed its ButtonSwitchFieldsComboOrderByTooltip value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnButtonSwitchFieldsComboOrderByTooltipPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
          DataFilter control = d as DataFilter;
          if (control == null) return;

          string newValue = e.NewValue as string;

          if (control.dgFilter != null && !string.IsNullOrEmpty(newValue))
            ((DynaObject)control.dgFilter.Resources[DATAFILTER_elementSwitchFieldsComboOrderByToolTip]).Value = newValue;
        }

        #endregion

        #region DependencyProperty DomainDataSource

        /// <summary>
        /// Identifies the DomainDataSource dependency property.
        /// </summary>
        public static readonly DependencyProperty DomainDataSourceProperty =
            DependencyProperty.Register(
                "DomainDataSource",
                typeof(DomainDataSource),
                typeof(DataFilter),
                new PropertyMetadata(OnDomainDataSourcePropertyChanged));

        /// <summary>
        /// DomainDataSource property changed handler.
        /// </summary>
        /// <param name="d">DataFilter that changed its DomainDataSource value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnDomainDataSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataFilter control = d as DataFilter;
            if (control == null)
            {
                return;
            }

            if (e.OldValue != null) {
              var old = e.OldValue as DomainDataSource;
              if (old != null)
                old.FilterDescriptors.CollectionChanged -= control.FilterDescriptorsChanged;
            }
            control.RefreshFilterItems();
            if (control.DomainDataSource != null)
              control.DomainDataSource.FilterDescriptors.CollectionChanged += control.FilterDescriptorsChanged;
        }

        void RefreshFilterItems()
        {
          DomainDataSource.GetDDSFilterDescriptorsCopy(DomainEntityFieldCollection.ToList(), dataGridFilterItems);
          RefreshControls();
        }

        void FilterDescriptorsChanged(object sender, Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
          // DomainDataSource.FilterDescriptors are changed by external control, master-detail case for example
          if (!changingFilterDescrs && ListenFilterDescriptorsChanges)
            RefreshFilterItems();
        }

        #endregion

        #region DependencyProperty ListenFilterDescriptorsChangesProperty

        /// <summary>
        /// Identifies the ListenFilterDescriptorsChangesProperty dependency property.
        /// </summary>
        public static readonly DependencyProperty ListenFilterDescriptorsChangesProperty =
            DependencyProperty.Register(
                "ListenFilterDescriptorsChangesProperty",
                typeof(bool),
                typeof(DataFilter),
                new PropertyMetadata(false/*defaultValue*/, OnListenFilterDescriptorsChangesPropertyChanged));

        /// <summary>
        /// ListenFilterDescriptorsChangesProperty changed handler.
        /// </summary>
        /// <param name="d">DataFilter that changed its ListenFilterDescriptorsChangesProperty value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnListenFilterDescriptorsChangesPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
          DataFilter control = d as DataFilter;
          if (control == null) {
            return;
          }
          if (e.NewValue != null) { }
        }

        #endregion

        #region DependencyProperty FilterPropertyPathHeader

        /// <summary>
        /// Identifies the FilterPropertyPathHeader dependency property.
        /// </summary>
        public static readonly DependencyProperty FilterPropertyPathHeaderProperty =
            DependencyProperty.Register(
                "FilterPropertyPathHeader",
                typeof(string),
                typeof(DataFilter),
                new PropertyMetadata(DATAFILTER_DefaultDataGridColumnFilterPropertyPath, OnFilterPropertyPathHeaderPropertyChanged));

        /// <summary>
        /// FilterPropertyPathHeader property changed handler.
        /// </summary>
        /// <param name="d">DataFilter that changed its FilterPropertyPathHeader value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnFilterPropertyPathHeaderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataFilter control = d as DataFilter;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.dgFilter != null &&
                !string.IsNullOrEmpty(newValue))
            {
              ((DynaString)control.dgFilter.Resources[DATAFILTER_elementDataGridColumnFilterPropertyPathHeader]).Value = newValue;
            }
        }

        #endregion

        #region DependencyProperty FilterOperationHeader

        /// <summary>
        /// Identifies the FilterOperationHeader dependency property.
        /// </summary>
        public static readonly DependencyProperty FilterOperationHeaderProperty =
            DependencyProperty.Register(
                "FilterOperationHeader",
                typeof(string),
                typeof(DataFilter),
                new PropertyMetadata(DATAFILTER_DefaultDataGridColumnFilterOperation, OnFilterOperationHeaderPropertyChanged));

        /// <summary>
        /// FilterOperationHeader property changed handler.
        /// </summary>
        /// <param name="d">DataFilter that changed its FilterOperationHeader value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnFilterOperationHeaderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataFilter control = d as DataFilter;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.dgcFilterOperation != null &&
                !string.IsNullOrEmpty(newValue))
            {
                control.dgcFilterOperation.Header = newValue;
            }
        }

        #endregion

        #region DependencyProperty FilterValueHeader

        /// <summary>
        /// Identifies the FilterValueHeader dependency property.
        /// </summary>
        public static readonly DependencyProperty FilterValueHeaderProperty =
            DependencyProperty.Register(
                "FilterValueHeader",
                typeof(string),
                typeof(DataFilter),
                new PropertyMetadata(DATAFILTER_DefaultDataGridColumnFilterValue, OnFilterValueHeaderPropertyChanged));

        /// <summary>
        /// FilterFieldNameHeader property changed handler.
        /// </summary>
        /// <param name="d">DataFilter that changed its FilterFieldNameHeader value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnFilterValueHeaderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataFilter control = d as DataFilter;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.dgcFilterValue != null &&
                !string.IsNullOrEmpty(newValue))
            {
                control.dgcFilterValue.Header = newValue;
            }
        }

        #endregion

        #region DependencyProperty FilterIgnoreValueHeader

        /// <summary>
        /// Identifies the FilterIgnoreValueHeader dependency property.
        /// </summary>
        public static readonly DependencyProperty FilterIgnoreValueHeaderProperty =
            DependencyProperty.Register(
                "FilterIgnoreValueHeader",
                typeof(string),
                typeof(DataFilter),
                new PropertyMetadata(DATAFILTER_DefaultDataGridColumnFilterIgnoreValue, OnFilterIgnoreValueHeaderPropertyChanged));

        /// <summary>
        /// FilterIgnoreValueHeader property changed handler.
        /// </summary>
        /// <param name="d">DataFilter that changed its FilterIgnoreValueHeader value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnFilterIgnoreValueHeaderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataFilter control = d as DataFilter;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.dgcFilterIgnoreValue == null || string.IsNullOrWhiteSpace(newValue))
            {
                return;
            }

            control.dgcFilterIgnoreValue.Header = newValue;
        }

        #endregion

        #region DependencyProperty FilterIgnoreValueHeader

        /// <summary>
        /// Identifies the FilterIsCaseSensitiveHeader dependency property.
        /// </summary>
        public static readonly DependencyProperty FilterIsCaseSensitiveHeaderProperty =
            DependencyProperty.Register(
                "FilterIsCaseSensitiveHeader",
                typeof(string),
                typeof(DataFilter),
                new PropertyMetadata(DATAFILTER_DefaultDataGridColumnFilterIsCaseSensitive, OnFilterIsCaseSensitiveHeaderPropertyChanged));

        /// <summary>
        /// FilterIsCaseSensitiveHeader property changed handler.
        /// </summary>
        /// <param name="d">DataFilter that changed its FilterIsCaseSensitiveHeader value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnFilterIsCaseSensitiveHeaderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataFilter control = d as DataFilter;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.dgcFilterIsCaseSensitive == null || string.IsNullOrWhiteSpace(newValue))
            {
                return;
            }

            control.dgcFilterIsCaseSensitive.Header = newValue;
        }

        #endregion

        #region DependencyProperty ExcludeFieldList

        /// <summary>
        /// Identifies the ExcludeFieldList dependency property.
        /// </summary>
        public static readonly DependencyProperty ExcludeFieldListProperty =
            DependencyProperty.Register(
            "ExcludeFieldList",
            typeof(string),
            typeof(DataFilter),
            new PropertyMetadata(string.Empty, OnExcludeFieldListPropertyChanged));

        /// <summary>
        /// ExcludeFieldList property changed handler.
        /// </summary>
        /// <param name="d">DataFilter that changed its ExcludeFieldList value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnExcludeFieldListPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataFilter control = d as DataFilter;
            if (control == null)
            {
                return;
            }

            //control.ExcludeFieldList = (e.NewValue as string);
        }

        #endregion

        #region DependencyProperty IncludeFieldList

        /// <summary>
        /// Identifies the IncludeFieldList dependency property.
        /// </summary>
        public static readonly DependencyProperty IncludeFieldListProperty =
            DependencyProperty.Register(
            "IncludeFieldList",
            typeof(string),
            typeof(DataFilter),
            new PropertyMetadata(string.Empty, OnIncludeFieldListPropertyChanged));

        /// <summary>
        /// IncludeFieldList property changed handler.
        /// </summary>
        /// <param name="d">DataFilter that changed its IncludeFieldList value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnIncludeFieldListPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataFilter control = d as DataFilter;
            if (control == null)
            {
                return;
            }

            //control.IncludeFieldList = (e.NewValue as string);
        }

        #endregion

        #region DependencyProperty EntityFieldsComboOrderBy

        public static readonly DependencyProperty EntityFieldsComboOrderByProperty =
            DependencyProperty.Register(
            "EntityFieldsComboOrderBy",
            typeof(EntityFieldsOrder),
            typeof(DataFilter),
            new PropertyMetadata(EntityFieldsOrder.Alphabetical, OnEntityFieldsComboOrderByPropertyChanged));

        public EntityFieldsOrder EntityFieldsComboOrderBy
        {
          get { return (EntityFieldsOrder)GetValue(EntityFieldsComboOrderByProperty); }
          set { SetValue(EntityFieldsComboOrderByProperty, value); }
        }

        private static void OnEntityFieldsComboOrderByPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
          DataFilter control = d as DataFilter;
          if (control == null) return;
          control.SetFieldsComboOrderByImage();
          control.RefreshListOfDomainEntityFields();
        }

        private void SetFieldsComboOrderByImage()
        {
          switch (EntityFieldsComboOrderBy) {
            case EntityFieldsOrder.Alphabetical:
              var img = new BitmapImage(new Uri(@"/System.Windows.Controls.Data.RIADataFilter.Control;component/Images/Alphabet.png", UriKind.Relative));
              ((DynaObject)this.dgFilter.Resources[DATAFILTER_elementFieldsComboOrderByImage]).Value = img;
              break;
            case EntityFieldsOrder.DisplayOrder:
              img = new BitmapImage(new Uri(@"/System.Windows.Controls.Data.RIADataFilter.Control;component/Images/Numbering.png", UriKind.Relative));
              ((DynaObject)this.dgFilter.Resources[DATAFILTER_elementFieldsComboOrderByImage]).Value = img;
              break;
          }
        }

        #endregion

        #endregion

        #region Private Properties

        #region Private Property FilterOperatorWithEntityFieldTypes

        /// <summary>
        /// Class that stores FilterOperators and these target FieldTypes
        /// </summary>
        private FilterOperatorWithFieldTypes FilterOperatorWithEntityFieldTypes = new FilterOperatorWithFieldTypes();

        #endregion

        #region Private Property dataGridFilterItems

        private List<DataGridFilterItem> dataGridFilterItems { get; set; }

        #endregion

        #region Private Property btnAddFilter

        /// <summary>
        /// Private accessor to btnAddFilter Button.
        /// </summary>
        private ButtonBase btnAddFilter { get; set; }

        #endregion

        #region Private Property btnDeleteFilter

        /// <summary>
        /// Private accessor to btnDeleteFilter Button.
        /// </summary>
        private ButtonBase btnDeleteFilter { get; set; }
        private ICommand deleteCmd { get; set; }

        #endregion

        #region Private Property btnClearFilter

        /// <summary>
        /// Private accessor to btnClearFilter Button.
        /// </summary>
        private ButtonBase btnClearFilter { get; set; }
        private ICommand clearCmd { get; set; }

        #endregion

        #region Private Property btnApply

        /// <summary>
        /// Private accessor to btnApply Button.
        /// </summary>
        private ButtonBase btnApply { get; set; }
        private ICommand applyCmd { get; set; }

        #endregion

        #region Private Property btnCancel

        /// <summary>
        /// Private accessor to btnCancel Button.
        /// </summary>
        private ButtonBase btnCancel { get; set; }
        private ICommand cancelCmd { get; set; }

        #endregion

        #region Private Property dgFilter

        /// <summary>
        /// Private accessor to dgFilter DataGrid.
        /// </summary>
        private DataGrid dgFilter { get; set; }

        #endregion

        #region Private Property dgcFilterPropertyPath

        /// <summary>
        /// Private accessor to dgcFilterPropertyPath DataGrid Column.
        /// </summary>
        private DataGridColumn dgcFilterPropertyPath { get; set; }

        #endregion

        #region Private Property dgcFilterOperation

        /// <summary>
        /// Private accessor to dgcFilterOperation DataGrid Column.
        /// </summary>
        private DataGridColumn dgcFilterOperation { get; set; }

        #endregion

        #region Private Property dgcFilterValue

        /// <summary>
        /// Private accessor to dgcFilterValue DataGrid Column.
        /// </summary>
        private DataGridColumn dgcFilterValue { get; set; }

        #endregion

        #region Private Property dgcFilterIgnoreValue

        /// <summary>
        /// Private accessor to dgcFilterIgnoreValue DataGrid Column.
        /// </summary>
        private DataGridColumn dgcFilterIgnoreValue { get; set; }

        #endregion

        #region Private Property dgcFilterIsCaseSensitive

        /// <summary>
        /// Private accessor to dgcFilterIsCaseSensitive DataGrid Column.
        /// </summary>
        private DataGridColumn dgcFilterIsCaseSensitive { get; set; }

        #endregion

        #region Private Property deleteRowCmd

        private ICommand deleteRowCmd { get; set; }

        #endregion

        #region Private Property switchFieldsComboOrderByCmd

        private ICommand switchFieldsComboOrderByCmd { get; set; }

        #endregion

        #endregion

        #region Public Properties

        #region Public Property DomainEntityFieldCollection

        /// <summary>
        /// Gets or Sets DomainEntityFieldCollection that stores user-frendly EntityField names
        /// </summary>
        public DomainEntityFieldCollection DomainEntityFieldCollection
        {
            get
            {
                return GetValue(DomainEntityFieldCollectionProperty) as DomainEntityFieldCollection;
            }
            set
            {
                SetValue(DomainEntityFieldCollectionProperty, value);
            }
        }

        #endregion

        #region Public Property FilterOperatorLocalizationCollection

        public FilterOperatorLocalizationCollection FilterOperatorLocalizationCollection
        {
            get
            {
                return GetValue(FilterOperatorLocalizationCollectionProperty) as FilterOperatorLocalizationCollection;
            }
            set
            {
                SetValue(FilterOperatorLocalizationCollectionProperty, value);
            }
        }

        #endregion

        #region Public Property ListOfDomainEntityField

        /// <summary>
        /// Gets the General list of DomainEntityField that stores EntityFields, mixing values with DomainEntityFieldCollection
        /// </summary>
        public List<DomainEntityField> ListOfDomainEntityFields { get; private set; }

        #endregion

        #region Public Property ButtonAddFilterTooltip

        /// <summary>
        /// Gets or sets the Tooltip of the AddFilter Button.
        /// </summary>
        public string ButtonAddFilterTooltip
        {
            get
            {
                return this.GetValue(ButtonAddFilterTooltipProperty) as string;
            }

            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(ButtonAddFilterTooltipProperty, value);
                }
            }
        }

        #endregion

        #region Public Property ButtonDeleteFilterTooltip

        /// <summary>
        /// Gets or sets the Tooltip of the DeleteFilter Button.
        /// </summary>
        public string ButtonDeleteFilterTooltip
        {
            get
            {
                return this.GetValue(ButtonDeleteFilterTooltipProperty) as string;
            }

            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(ButtonDeleteFilterTooltipProperty, value);
                }
            }
        }

        #endregion

        #region Public Property ButtonClearFilterTooltip

        /// <summary>
        /// Gets or sets the Tooltip of the ClearFilter Button.
        /// </summary>
        public string ButtonClearFilterTooltip
        {
            get
            {
                return this.GetValue(ButtonClearFilterTooltipProperty) as string;
            }

            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(ButtonClearFilterTooltipProperty, value);
                }
            }
        }

        #endregion

        #region Public Property ButtonApplyTooltip

        /// <summary>
        /// Gets or sets the Tooltip of the Apply Button.
        /// </summary>
        public string ButtonApplyTooltip
        {
            get
            {
                return this.GetValue(ButtonApplyTooltipProperty) as string;
            }

            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(ButtonApplyTooltipProperty, value);
                }
            }
        }

        #endregion

        #region Public Property ButtonCancelTooltip

        /// <summary>
        /// Gets or sets the Tooltip of the Cancel Button.
        /// </summary>
        public string ButtonCancelTooltip
        {
            get
            {
                return this.GetValue(ButtonCancelTooltipProperty) as string;
            }

            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(ButtonCancelTooltipProperty, value);
                }
            }
        }

        #endregion

        #region Property ButtonSwitchFieldsComboOrderByTooltip

        /// <summary>
        /// Gets or sets the Tooltip of the SwitchFieldsComboOrderBy Button.
        /// </summary>
        public string ButtonSwitchFieldsComboOrderByTooltip
        {
          get
          {
            return this.GetValue(ButtonSwitchFieldsComboOrderByTooltipProperty) as string;
          }

          set
          {
            if (!string.IsNullOrEmpty(value))
            {
              this.SetValue(ButtonSwitchFieldsComboOrderByTooltipProperty, value);
            }
          }
        }

        #endregion

        #region Public Property ButtonApplyContent

        /// <summary>
        /// Gets or sets the Content of the Apply Button.
        /// </summary>
        public string ButtonApplyContent
        {
            get
            {
                return this.GetValue(ButtonApplyContentProperty) as string;
            }
            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(ButtonApplyContentProperty, value);
                }
            }
        }

        #endregion

        #region Public Property ButtonCancelContent

        /// <summary>
        /// Gets or sets the Content of the Cancel button.
        /// </summary>
        public string ButtonCancelContent
        {
            get
            {
                return this.GetValue(ButtonCancelContentProperty) as string;
            }
            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(ButtonCancelContentProperty, value);
                }
            }
        }

        #endregion

        #region Public Property DomainDataSource

        /// <summary>
        /// Gets or sets a DomainDataSource.
        /// </summary>
        public DomainDataSource DomainDataSource
        {
            get
            {
                return this.GetValue(DomainDataSourceProperty) as DomainDataSource;
            }
            set
            {
                this.SetValue(DomainDataSourceProperty, value);
            }
        }

        #endregion

        #region Public Property ListenFilterDescriptorsChanges

        [DefaultValue(false)]
        public bool ListenFilterDescriptorsChanges
        {
          get { return (bool)this.GetValue(ListenFilterDescriptorsChangesProperty); }
          set { this.SetValue(ListenFilterDescriptorsChangesProperty, value); }
        }

        #endregion

        #region Public Property FilterPropertyPathHeader

        /// <summary>
        /// Gets or sets the Header of the FilterPropertyPath.
        /// </summary>
        public string FilterPropertyPathHeader
        {
            get
            {
                return this.GetValue(FilterPropertyPathHeaderProperty) as string;
            }
            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(FilterPropertyPathHeaderProperty, value);
                }
            }
        }

        #endregion

        #region Public Property FilterOperationHeader

        /// <summary>
        /// Gets or sets the Header of the FilterOperation.
        /// </summary>
        public string FilterOperationHeader
        {
            get
            {
                return this.GetValue(FilterOperationHeaderProperty) as string;
            }
            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(FilterOperationHeaderProperty, value);
                }
            }
        }

        #endregion

        #region Public Property FilterValueHeader

        /// <summary>
        /// Gets or sets the Header of the FilterValue.
        /// </summary>
        public string FilterValueHeader
        {
            get
            {
                return this.GetValue(FilterValueHeaderProperty) as string;
            }
            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(FilterValueHeaderProperty, value);
                }
            }
        }

        #endregion

        #region Public Property FilterIgnoreValueHeader

        /// <summary>
        /// Gets or sets the Header of the FilterIgnoreValue.
        /// </summary>
        public string FilterIgnoreValueHeader
        {
            get
            {
                return this.GetValue(FilterIgnoreValueHeaderProperty) as string;
            }
            set
            {
                if (!string.IsNullOrWhiteSpace(value))
                {
                    this.SetValue(FilterIgnoreValueHeaderProperty, value);
                }
            }
        }

        #endregion

        #region Public Property FilterIgnoreValueHeader

        /// <summary>
        /// Gets or sets the Header of the FilterIsCaseSensitive.
        /// </summary>
        public string FilterIsCaseSensitiveHeader
        {
            get
            {
                return this.GetValue(FilterIsCaseSensitiveHeaderProperty) as string;
            }
            set
            {
                if (!string.IsNullOrWhiteSpace(value))
                {
                    this.SetValue(FilterIsCaseSensitiveHeaderProperty, value);
                }
            }
        }

        #endregion

        #region Public Property ExcludeFieldList

        /// <summary>
        /// Gets or Sets the Field list than must be Ignored when filling field list for ComboBox
        /// </summary>
        public string ExcludeFieldList
        {
            get
            {
                return (string)GetValue(ExcludeFieldListProperty);
            }
            set
            {
                SetValue(ExcludeFieldListProperty, value);
            }
        }

        #endregion

        #region Public Property IncludeFieldList

        /// <summary>
        /// Gets or Sets the Field list than must be Added when filling field list for ComboBox
        /// </summary>
        public string IncludeFieldList
        {
            get
            {
                return (string)GetValue(IncludeFieldListProperty);
            }
            set
            {
                SetValue(IncludeFieldListProperty, value);
            }
        }

        #endregion

        #region Public Property OnApplyButtonBeforeClick

        public event EventHandler OnApplyButtonBeforeClick;

        #endregion

        #region Public Property OnCancelButtonBeforeClick

        public event EventHandler OnCancelButtonBeforeClick;

        #endregion

        #region Public Property OnApplyButtonAfterClick

        public event EventHandler OnApplyButtonAfterClick;

        #endregion

        #region Public Property OnCancelButtonAfterClick

        public event EventHandler OnCancelButtonAfterClick;

        #endregion

        #region Public Property OnCanCancel

        public event CanCancelEventHandler OnCanCancel;

        #endregion

        #region Public Property CellEditorPrepared

        public event EventHandler CellEditorPrepared;

        #endregion

        #endregion

        #region Constructors

        public DataFilter()
        {
            DefaultStyleKey = typeof(DataFilter);
            this.dataGridFilterItems = new List<DataGridFilterItem>();
            this.LayoutUpdated += OnDataFilterLayoutUpdated;
            applyCmd  = new DelegateCommand<object>(ApplyFilters , CanApplyFilters );
            cancelCmd = new DelegateCommand<object>(CancelFilters, CanCancelFilters);
            deleteCmd = new DelegateCommand<object>(DeleteFilterItem, CanDeleteFilterItem);
            clearCmd  = new DelegateCommand<object>(ClearFilterItem, CanClearFilterItem);
            deleteRowCmd = new DelegateCommand<object>(AsyncDeleteRowFilterItem, CanDeleteRowFilterItem);
            switchFieldsComboOrderByCmd = new DelegateCommand<object>(SwitchFieldsComboOrderBy, CanSwitchFieldsComboOrderBy);
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            #region Button AddFilter

            if (this.btnAddFilter != null)
            {
                this.btnAddFilter.Click -= new RoutedEventHandler(this.OnButtonAddFilterClick);
            }

            this.btnAddFilter = GetTemplateChild(DATAFILTER_elementButtonAddFilter) as ButtonBase;

            if (this.btnAddFilter != null)
            {
                this.btnAddFilter.Click += new RoutedEventHandler(this.OnButtonAddFilterClick);

                ToolTipService.SetToolTip(this.btnAddFilter, this.ButtonAddFilterTooltip);

                /*if (this.AddFilterButtonStyle != null)
                {
                    this._addFilterButton.SetBinding(ButtonBase.StyleProperty, new Binding("AddFilterButtonStyle") { Source = this });
                }*/
            }

            #endregion

            #region Button DeleteFilter

            if (this.btnDeleteFilter != null)
            {
                this.btnDeleteFilter.Command = null;
            }

            this.btnDeleteFilter = GetTemplateChild(DATAFILTER_elementButtonDeleteFilter) as ButtonBase;

            if (this.btnDeleteFilter != null)
            {
                this.btnDeleteFilter.Command = deleteCmd;

                ToolTipService.SetToolTip(this.btnDeleteFilter, this.ButtonDeleteFilterTooltip);

                /*if (this.DeleteFilterButtonStyle != null)
                {
                    this._deleteFilterButton.SetBinding(ButtonBase.StyleProperty, new Binding("DeleteFilterButtonStyle") { Source = this });
                }*/
            }

            #endregion

            #region Button ClearFilter

            if (this.btnClearFilter != null)
            {
                this.btnClearFilter.Command = null;
            }

            this.btnClearFilter = GetTemplateChild(DATAFILTER_elementButtonClearFilter) as ButtonBase;

            if (this.btnClearFilter != null)
            {
                this.btnClearFilter.Command = clearCmd;

                ToolTipService.SetToolTip(this.btnClearFilter, this.ButtonClearFilterTooltip);

                /*if (this.ClearFilterButtonStyle != null)
                {
                    this._clearFilterButton.SetBinding(ButtonBase.StyleProperty, new Binding("ClearFilterButtonStyle") { Source = this });
                }*/
            }

            #endregion

            #region Button Apply

            if (this.btnApply != null)
            {
                this.btnApply.Command = null;
            }

            this.btnApply = GetTemplateChild(DATAFILTER_elementButtonApply) as ButtonBase;

            if (this.btnApply != null)
            {
                this.btnApply.Command = applyCmd;
                this.btnApply.Content = this.ButtonApplyContent;

                ToolTipService.SetToolTip(this.btnApply, this.ButtonApplyTooltip);

                /*if (this.AddRecordButtonStyle != null)
                                {
                                    this._addRecordButton.SetBinding(ButtonBase.StyleProperty, new Binding("CancelButtonStyle") { Source = this });
                                }*/
            }

            #endregion

            #region Button Cancel

            if (this.btnCancel != null)
            {
                this.btnCancel.Command = null;
            }

            this.btnCancel = GetTemplateChild(DATAFILTER_elementButtonCancel) as ButtonBase;

            if (this.btnCancel != null)
            {
                this.btnCancel.Command = cancelCmd;
                this.btnCancel.Content = this.ButtonCancelContent;

                ToolTipService.SetToolTip(this.btnCancel, this.ButtonCancelTooltip);

                /*if (this.AddRecordButtonStyle != null)
                                {
                                    this._addRecordButton.SetBinding(ButtonBase.StyleProperty, new Binding("CancelButtonStyle") { Source = this });
                                }*/
            }

            #endregion

            #region DataGridColumn FilterPropertyPath

            this.dgcFilterPropertyPath = GetTemplateChild(DATAFILTER_elementDataGridColumnFilterPropertyPath) as DataGridColumn;

            if (this.dgcFilterPropertyPath != null) { }

            #endregion

            #region DataGridColumn FilterOperation

            this.dgcFilterOperation = GetTemplateChild(DATAFILTER_elementDataGridColumnFilterOperation) as DataGridColumn;

            if (this.dgcFilterOperation != null)
            {
                this.dgcFilterOperation.Header = this.FilterOperationHeader;
            }

            #endregion

            #region DataGridColumn FilterValue

            this.dgcFilterValue = GetTemplateChild(DATAFILTER_elementDataGridColumnFilterValue) as DataGridColumn;

            if (this.dgcFilterValue != null)
            {
                this.dgcFilterValue.Header = this.FilterValueHeader;
            }

            #endregion

            #region DataGridColumn FilterIgnoreValue

            this.dgcFilterIgnoreValue = GetTemplateChild(DATAFILTER_elementDataGridColumnFilterIgnoreValue) as DataGridColumn;

            if (this.dgcFilterIgnoreValue != null)
            {
                this.dgcFilterIgnoreValue.Header = this.FilterIgnoreValueHeader;
            }

            #endregion

            #region DataGridColumn FilterIsCaseSensitive

            this.dgcFilterIsCaseSensitive = GetTemplateChild(DATAFILTER_elementDataGridColumnFilterIsCaseSensitive) as DataGridColumn;

            if (this.dgcFilterIsCaseSensitive != null)
            {
                this.dgcFilterIsCaseSensitive.Header = this.FilterIsCaseSensitiveHeader;
            }

            #endregion

            #region DataGrid Filter

            if (this.dgFilter != null)
            {
                this.dgFilter.PreparingCellForEdit -= OnDataGridFilterPreparingCellForEdit;
                this.dgFilter.SelectionChanged     -= dgFilter_SelectionChanged;
                this.dgFilter.CurrentCellChanged   -= dgFilter_CurrentCellChanged;
                this.dgFilter.MouseLeftButtonUp    -= dgFilter_MouseLeftButtonUp;
                ((DynaCommand)this.dgFilter.Resources[DATAFILTER_elementDeleteRowCmd]).Value = null;
                ((DynaObject )this.dgFilter.Resources[DATAFILTER_elementDeleteRowToolTip]).Value = null;
                ((DynaCommand)this.dgFilter.Resources[DATAFILTER_elementSwitchFieldsComboOrderByCmd]).Value = null;
                ((DynaObject )this.dgFilter.Resources[DATAFILTER_elementSwitchFieldsComboOrderByToolTip]).Value = null;
                ((DynaObject )this.dgFilter.Resources[DATAFILTER_elementFieldsComboOrderByImage]).Value = null;
                ((DynaString )this.dgFilter.Resources[DATAFILTER_elementDataGridColumnFilterPropertyPathHeader]).Value = null;
            }

            this.dgFilter = GetTemplateChild(DATAFILTER_elementDataGridFilter) as DataGrid;

            if (this.dgFilter != null)
            {
                this.dgFilter.DataGridRefreshItemsSource(this.dataGridFilterItems);
                this.dgFilter.PreparingCellForEdit += OnDataGridFilterPreparingCellForEdit;
                this.dgFilter.SelectionChanged     += dgFilter_SelectionChanged;
                this.dgFilter.CurrentCellChanged   += dgFilter_CurrentCellChanged;
                this.dgFilter.MouseLeftButtonUp    += dgFilter_MouseLeftButtonUp;
                ((DynaCommand)this.dgFilter.Resources[DATAFILTER_elementDeleteRowCmd]).Value = deleteRowCmd;
                ((DynaObject )this.dgFilter.Resources[DATAFILTER_elementDeleteRowToolTip]).Value = this.ButtonDeleteFilterTooltip;
                ((DynaCommand)this.dgFilter.Resources[DATAFILTER_elementSwitchFieldsComboOrderByCmd]).Value = switchFieldsComboOrderByCmd;
                ((DynaObject )this.dgFilter.Resources[DATAFILTER_elementSwitchFieldsComboOrderByToolTip]).Value = this.ButtonSwitchFieldsComboOrderByTooltip;
                SetFieldsComboOrderByImage();
                ((DynaString )this.dgFilter.Resources[DATAFILTER_elementDataGridColumnFilterPropertyPathHeader]).Value = this.FilterPropertyPathHeader;
            }

            #endregion
        }

        void dgFilter_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
          deleteCmd.CanExecute(null);
          deleteRowCmd.CanExecute(null);
        }

        void dgFilter_CurrentCellChanged(object sender, EventArgs e)
        {
          dgFilter.BeginEdit();
        }

        void dgFilter_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
          if (dgFilter.CurrentColumn is DataGridCheckBoxColumn && dgFilter.SelectedItem != null)
          { // if DataGridCheckBoxColumn is wide then CheckBox can be toggled by clicking to any "white" area of column
            var c = dgFilter.CurrentColumn.GetCellContent(dgFilter.SelectedItem);
            if (c is CheckBox)
              if ((c as CheckBox) == preparedCheckBox)
                preparedCheckBox = null; // already processed by OnDataGridFilterPreparingCellForEdit
              else
                (c as CheckBox).IsChecked = !(c as CheckBox).IsChecked;
          }
        }

        #endregion

        #region Private Methods

        #region Private Method RefreshListOfDomainEntityFields

        private void RefreshListOfDomainEntityFields()
        {
          if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this) && this.DomainDataSource != null)
          {
            var fields = Utilities.GetListOfDomainEntityFields(this.DomainDataSource, Utilities.ParseStringAsListOfString(this.IncludeFieldList), Utilities.ParseStringAsListOfString(this.ExcludeFieldList), this.DomainEntityFieldCollection);
            switch (EntityFieldsComboOrderBy) {
              case EntityFieldsOrder.Alphabetical : fields = fields.OrderBy(r => r.DisplayName).ToList(); break;
              case EntityFieldsOrder.DisplayOrder : fields = fields.OrderBy(r => r.OrderId    ).ToList(); break;
            }
            this.ListOfDomainEntityFields = fields;
          }
        }

        #endregion

        #region Private Method OnDataFilterLayoutUpdated

        private void OnDataFilterLayoutUpdated(object sender, EventArgs e)
        {
          if (this.ListOfDomainEntityFields == null)
            RefreshListOfDomainEntityFields();
        }

        #endregion

        #region Private Method RefreshCommands

        private void RefreshCommands()
        {
          this.applyCmd.CanExecute(null);
          this.cancelCmd.CanExecute(null);
          this.deleteCmd.CanExecute(null);
          this.clearCmd.CanExecute(null);
          this.deleteRowCmd.CanExecute(null);
        }

        #endregion

        #region Private Method RefreshControls

        private void RefreshControls()
        {
          this.dgFilter.DataGridRefreshItemsSource(this.dataGridFilterItems);
          RefreshCommands();
        }

        #endregion

        #region Private Method OnButtonAddFilterClick

        /// <summary>
        /// Handles the click of the AddFilter button.
        /// </summary>
        /// <param name="sender">The button.</param>
        /// <param name="e">The event args.</param>
        private void OnButtonAddFilterClick(object sender, RoutedEventArgs e)
        {
            this.AddFilterItem();
        }

        #endregion

        #region Private Method OnDataGridFilterPreparingCellForEdit

        /// <summary>
        /// Preparing DataGrid cell for edit.
        /// </summary>
        /// <param name="sender">DataGrid</param>
        /// <param name="e">DataGridPreparingCellForEditEventArgs</param>
        private void OnDataGridFilterPreparingCellForEdit(object sender, DataGridPreparingCellForEditEventArgs e)
        {
            DataGridFilterItem dgSelectedItem = (this.dgFilter.SelectedItem as DataGridFilterItem);
            FrameworkElement editingElement = e.EditingElement;

            if (editingElement == null)
            {
                return;
            }

            string columnName = e.Column.GetValue(FrameworkElement.NameProperty) as string;

            if (string.IsNullOrWhiteSpace(columnName))
            {
                return;
            }

            preparedCheckBox = null;
            bool processed = false;
            switch (columnName)
            {
                ////Initialized dgcFilterPropertyPath DataGridTemplateColumn.CellEditingTemplate
                case DATAFILTER_elementDataGridColumnFilterPropertyPath:
                    if (editingElement.GetType() == typeof(ComboBox))
                    {
                        ComboBox element = e.EditingElement as ComboBox;

                        if (element == null)
                        {
                            return;
                        }

                        element.SelectionChanged -= this.OnFilterPropertyPathComboBoxSelectionChanged;
                        element.DisplayMemberPath = "DisplayName";
                        element.ItemsSource = this.ListOfDomainEntityFields;
                        if (this.dgFilter.SelectedItem != null)
                        {
                            element.SelectedItem = this.ListOfDomainEntityFields.FirstOrDefault(r => r.PropertyPath == dgSelectedItem.FilterDescriptor.PropertyPath);
                        }
                        element.SelectionChanged += this.OnFilterPropertyPathComboBoxSelectionChanged;
                        processed = true;
                    }
                    break;

                ////Initialized dgcFilterOperation DataGridTemplateColumn.CellEditingTemplate
                case DATAFILTER_elementDataGridColumnFilterOperation:
                    if (editingElement.GetType() == typeof(ComboBox))
                    {
                        ComboBox element = e.EditingElement as ComboBox;

                        var filterOperatorList = Utilities.GetListOfFilterOperatorNames(this.FilterOperatorLocalizationCollection, this.FilterOperatorWithEntityFieldTypes.GetFilterOperatorListByFieldType(dgSelectedItem.FieldType));

                        if (element == null)
                        {
                            return;
                        }

                        element.SelectionChanged -= this.OnFilterOperationComboBoxSelectionChanged;
                        element.ItemsSource = filterOperatorList;

                        if (this.dgFilter.SelectedItem != null)
                        {
                            element.SelectedItem = filterOperatorList.FirstOrDefault(r => r == Utilities.GetLocalizationByFilterOperator(dgSelectedItem.FilterDescriptor.Operator, this.FilterOperatorLocalizationCollection));
                        }
                        element.SelectionChanged += this.OnFilterOperationComboBoxSelectionChanged;
                        processed = true;
                    }
                    break;

                ////Initialized dgcFilterValue DataGridTemplateColumn.CellEditingTemplate
                /*case 2:
                    if (editingElement.GetType() == typeof(TextBox))
                    {
                        TextBox element = editingElement as TextBox;
                        element.TextInput -= element_TextInput;
                        element.TextInput += element_TextInput;
                    }
                    break;*/
            }

            if (!processed) {
              if (editingElement is TextBox) {
                (editingElement as TextBox).TextChanged -= DataGridFilter_CellTextChanged;
                (editingElement as TextBox).TextChanged += DataGridFilter_CellTextChanged;
                processCellChanges(editingElement);
              }
              else if (editingElement is CheckBox) {
                (editingElement as CheckBox).Click -= DataGridFilter_CellCheckBoxClick;
                (editingElement as CheckBox).Click += DataGridFilter_CellCheckBoxClick;
                if (e.Column is DataGridCheckBoxColumn && editingElement == FocusManager.GetFocusedElement())
                { // one click start editing support for DataGridCheckBoxColumn
                  (editingElement as CheckBox).IsChecked = !(editingElement as CheckBox).IsChecked;
                  preparedCheckBox = editingElement as CheckBox;
                }
                processCellChanges(editingElement);
              }
            }

            if (CellEditorPrepared != null)
              CellEditorPrepared(editingElement, null);
        }

        private CheckBox preparedCheckBox = null;

        void processCellChanges(object ed)
        {
          if (ed is CheckBox) {
            var be = (ed as CheckBox).GetBindingExpression(CheckBox.IsCheckedProperty);
            if (be != null) be.UpdateSource();
            RefreshCommands();
          }
          else if (ed is TextBox) {
            var be = (ed as TextBox).GetBindingExpression(TextBox.TextProperty);
            if (be != null) be.UpdateSource();
            RefreshCommands();
          }
        }

        void DataGridFilter_CellCheckBoxClick(object sender, RoutedEventArgs e)
        {
          processCellChanges(sender);
        }

        void DataGridFilter_CellTextChanged(object sender, TextChangedEventArgs e)
        {
          processCellChanges(sender);
        }

        /*private void element_TextInput(object sender, Input.TextCompositionEventArgs e)
         {
             TextBox textBox = (sender as TextBox);
             DataGridFilterItem record = (this.dgFilter.SelectedItem as DataGridFilterItem);

             if (textBox == null || record == null)
             {
                 return;
             }

             if (record.FieldType == typeof(int))
             {
                 var regex = new Regex(@"[0-9]*");
                 if (regex.IsMatch(e.Text))
                 {
                     e.Handled = true;
                 }
                 //textBox.Text = regex.Match(e.Text).Value;
                 regex = null;
             }
         }*/

        #endregion

        #region Private Method OnFilterPropertyPathComboBoxSelectionChanged

        /// <summary>
        /// Changes PropertyPath value for selected filter item.
        /// </summary>
        /// <param name="sender">ComboBox</param>
        /// <param name="e">SelectionChangedEventArgs</param>
        private void OnFilterPropertyPathComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            DomainEntityField result = ((ComboBox)sender).SelectedItem as DomainEntityField;
            DataGridFilterItem record = (this.dgFilter.SelectedItem as DataGridFilterItem);

            if (this.dgFilter.SelectedItem == null ||
                result == null ||
                record == null)
            {
                return;
            }

            record.FilterDescriptor.PropertyPath = result.PropertyPath;

            var filterOperatorListByFieldType = this.FilterOperatorWithEntityFieldTypes.GetFilterOperatorListByFieldType(record.FieldType);

            if (filterOperatorListByFieldType == null ||
                filterOperatorListByFieldType.Count == 0)
            {
                RefreshCommands();
                return;
            }

            if (!filterOperatorListByFieldType.Contains(record.FilterDescriptor.Operator))
            {
                record.FilterDescriptor.Operator = filterOperatorListByFieldType[0];
            }

            RefreshCommands();
        }

        #endregion

        #region Private Method OnFilterOperationComboBoxSelectionChanged

        /// <summary>
        /// Changes Operator value for selected filter item.
        /// </summary>
        /// <param name="sender">ComboBox</param>
        /// <param name="e">SelectionChangedEventArgs</param>
        private void OnFilterOperationComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            string result = ((ComboBox)sender).SelectedItem as string;

            if (this.dataGridFilterItems == null ||
                this.dataGridFilterItems.Count == 0 ||
                this.dgFilter.SelectedItem == null ||
                result == null)
            {
                return;
            }

            DataGridFilterItem record = (this.dgFilter.SelectedItem as DataGridFilterItem);
            record.FilterDescriptor.Operator = Utilities.GetFilterOperatorByLocalization(result, this.FilterOperatorLocalizationCollection);
            RefreshCommands();
        }

        #endregion

        #region Private Method AddFilterItem

        /// <summary>
        /// Add new filter item.
        /// </summary>
        /// <returns>bool</returns>
        private bool AddFilterItem()
        {
            if (this.ListOfDomainEntityFields == null ||
                this.ListOfDomainEntityFields.Count == 0)
            {
                if (System.Diagnostics.Debugger.IsAttached)
                {
                    System.Diagnostics.Debug.WriteLine("Method: AddFilterItem, ListOfDomainEntityFields == null OR ListOfDomainEntityFields.Count == 0, exiting.");
                }
                return false;
            }

            var filterOperatorList = Utilities.GetListOfFilterOperatorNames(this.FilterOperatorLocalizationCollection, this.FilterOperatorWithEntityFieldTypes.GetFilterOperatorListByFieldType(this.ListOfDomainEntityFields[0].PropertyType));

            if (this.dataGridFilterItems == null ||
                filterOperatorList == null ||
                filterOperatorList.Count == 0)
            {
                if (System.Diagnostics.Debugger.IsAttached)
                {
                    System.Diagnostics.Debug.WriteLine("Method: AddFilterItem, dataGridFilterItems == null OR filterOperatorList == null OR filterOperatorList.Count == 0, exiting.");
                }
                return false;
            }

            this.dataGridFilterItems.Add(
                new DataGridFilterItem(this.ListOfDomainEntityFields)
                {
                    FilterDescriptor = new FilterDescriptor() { PropertyPath = this.ListOfDomainEntityFields[0].PropertyPath, Operator = Utilities.GetFilterOperatorByLocalization(filterOperatorList[0], this.FilterOperatorLocalizationCollection), Value = "0", IgnoredValue = string.Empty }
                });
            RefreshControls();

            return true;
        }

        #endregion

        #region Private Method DeleteFilterItem

        /// <summary>
        /// Delete selected filter items from list.
        /// </summary>
        private void DeleteFilterItem(object param)
        {
            if (this.dataGridFilterItems == null ||
                this.dataGridFilterItems.Count == 0 ||
                this.dgFilter.SelectedItem == null)
            {
                return;
            }

            if (dgFilter.SelectedItems.Count > 1) {
              var lst = new List<object>();
              foreach (var i in dgFilter.SelectedItems) lst.Add(i);
              foreach (var j in lst) this.dataGridFilterItems.Remove((DataGridFilterItem)j);
            }
            else this.dataGridFilterItems.Remove((DataGridFilterItem)this.dgFilter.SelectedItem);

            RefreshControls();
        }

        private bool CanDeleteFilterItem(object param)
        {
          return this.dataGridFilterItems != null && this.dataGridFilterItems.Count > 0 &&
                 this.dgFilter != null && this.dgFilter.SelectedItem != null;
        }

        #endregion

        #region Private Method DeleteRowFilterItem

        /// <summary>
        /// Delete selected filter item from list.
        /// </summary>
        private void DeleteRowFilterItem(object param)
        {
          if (this.dataGridFilterItems == null ||
              this.dataGridFilterItems.Count == 0 ||
              this.dgFilter.SelectedItem == null || dgFilter.SelectedItems.Count != 1)
          {
            return;
          }

          this.dataGridFilterItems.Remove((DataGridFilterItem)this.dgFilter.SelectedItem);
          RefreshControls();
        }

        private void AsyncDeleteRowFilterItem(object param)
        {
          // in grid DeleteRowBtn defines ClickMode="Press", that's why we cannot delete right away, UI is not "stable" yet and must finish its work
          // also SelectedItem won't be changed as it happens in ClickMode="Release", so we must do it manually

          DataGridFilterItem rowItem = null;
          if (param is FrameworkElement && ((FrameworkElement)param).DataContext is DataGridFilterItem)
            rowItem = ((FrameworkElement)param).DataContext as DataGridFilterItem;

          this.Dispatcher.BeginInvoke(delegate {
            if (rowItem != null) dgFilter.SelectedItem = rowItem;
            DeleteRowFilterItem(param);
          });
        }

        private bool CanDeleteRowFilterItem(object param)
        {
          return this.dataGridFilterItems != null && this.dataGridFilterItems.Count > 0 &&
                 this.dgFilter != null && this.dgFilter.SelectedItem != null && dgFilter.SelectedItems.Count == 1;
        }

        #endregion

        #region Private Method ClearFilterItem

        /// <summary>
        /// Clear filter list.
        /// </summary>
        private void ClearFilterItem(object param = null)
        {
            if (this.dataGridFilterItems == null ||
                this.dataGridFilterItems.Count == 0)
            {
                return;
            }

            while (this.dataGridFilterItems.Count > 0)
            {
                this.dataGridFilterItems.RemoveAt(0);
            }
            RefreshControls();
        }

        private bool CanClearFilterItem(object param)
        {
          return this.dataGridFilterItems != null && this.dataGridFilterItems.Count > 0;
        }

        #endregion

        #region Private Method SwitchFieldsComboOrderBy

        /// <summary>
        /// Delete selected filter item from list.
        /// </summary>
        private void SwitchFieldsComboOrderBy(object param)
        {
          switch (EntityFieldsComboOrderBy) {
            case EntityFieldsOrder.Alphabetical :
              dgFilter.CommitEdit();
              EntityFieldsComboOrderBy = EntityFieldsOrder.DisplayOrder;
              break;
            case EntityFieldsOrder.DisplayOrder :
              dgFilter.CommitEdit();
              EntityFieldsComboOrderBy = EntityFieldsOrder.Alphabetical;
              break;
          }
        }

        private bool CanSwitchFieldsComboOrderBy(object param)
        {
          return (EntityFieldsComboOrderBy == EntityFieldsOrder.Alphabetical ||
                  EntityFieldsComboOrderBy == EntityFieldsOrder.DisplayOrder);
        }

        #endregion

        #endregion

        #region Public Methods

        #region Private Method ApplyFilters

        /// <summary>
        /// Apply and add filter intems to the DomainDataSource.
        /// </summary>
        public void ApplyFilters(object param = null)
        {
            if (this.OnApplyButtonBeforeClick != null)
            {
                this.OnApplyButtonBeforeClick(this, null);
            }

            if (this.DomainDataSource != null)
            {
                changingFilterDescrs = true;
                try {
                  this.DomainDataSource.IsEnabled = false;
                  this.DomainDataSource.SetToDDSFilterDescriptorsCopy(this.dataGridFilterItems);
                  this.DomainDataSource.IsEnabled = true;
                }
                finally {
                  changingFilterDescrs = false;
                };
            }

            if (this.OnApplyButtonAfterClick != null)
            {
                this.OnApplyButtonAfterClick(this, null);
                if (this.DomainDataSource != null && !ListenFilterDescriptorsChanges)
                {
                  // rereading from the current state of dds (in case FilterDescriptors were postprocessed by OnApplyButtonAfterClick)
                  this.DomainDataSource.IsEnabled = false;
                  this.DomainDataSource.GetDDSFilterDescriptorsCopy(this.ListOfDomainEntityFields, this.dataGridFilterItems);
                  this.DomainDataSource.IsEnabled = true;
                  RefreshControls();
                  return;
                }
            }

            if (this.DomainDataSource != null) {
              this.applyCmd.CanExecute(null);
              this.cancelCmd.CanExecute(null);
            }
        }

        public bool CanApplyFilters(object param)
        {
          if (this.DomainDataSource != null)
            return !this.DomainDataSource.DDSFilterDescriptorsEqual(this.dataGridFilterItems);
          else
            return false;
        }

        private bool changingFilterDescrs = false;

        #endregion

        #region Private Method CancelFilters

        /// <summary>
        /// Cancel filter items of the DomainDataSource.
        /// </summary>
        public void CancelFilters(object param = null)
        {
            if (this.OnCancelButtonBeforeClick != null)
            {
                this.OnCancelButtonBeforeClick(this, null);
            }

            if (this.DomainDataSource != null)
            {
                this.DomainDataSource.IsEnabled = false;
                this.DomainDataSource.GetDDSFilterDescriptorsCopy(this.ListOfDomainEntityFields, this.dataGridFilterItems);
                this.DomainDataSource.IsEnabled = true;
            }

            if (this.OnCancelButtonAfterClick != null)
            {
                changingFilterDescrs = true;
                try {
                  this.OnCancelButtonAfterClick(this, null);
                }
                finally {
                  changingFilterDescrs = false;
                }
            }

            if (this.DomainDataSource != null)
              RefreshControls(); // Apply-Clear-Cancel scenario, UI must be refreshed
        }

        public bool CanCancelFilters(object param)
        {
          if (this.DomainDataSource != null) {
            if (this.OnCanCancel != null) return OnCanCancel(this, null);
                                     else return this.DomainDataSource.FilterDescriptors.Count > 0;
          }
          else return false;
        }

        #endregion

        #endregion
    }
}
